import java.util.LinkedList;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BasicTicketSaleSystem {
	static TicketSaleSystem system;
	static final long MS=1000;
	static int waitTime=2;
	public static void main(String[] args) {
		System.out.println("**欢迎使用抢票模拟系统**");
		while (true){
			try {
				system = new TicketSaleSystem(
						GoldfishReader.readInt("请输入计划总放票数量"),
						GoldfishReader.readInt("请输入初始放票量"),
						GoldfishReader.readInt("请输入购票人数")
				);
				break;
			}catch (Exception e){
				System.out.println(e.getMessage());
				system=null;
			}
		}
		System.out.println("票已经印刷完毕,"+waitTime+"秒后发售");
		try{
			Thread.sleep(waitTime * MS);
		}catch (Exception e){}
		system.startSale();

		for (int i = 0, finishCount = 0;
			 finishCount < system.basicBuyerQueue.size();
			 i = (i + 1) % system.basicBuyerQueue.size()) {
			if (system.basicBuyerQueue.get(i).finished)
				finishCount++;
			else
				finishCount = 0;
		}
//			try{
//				Thread.currentThread().join();
//			}catch (Exception e){
//				System.out.println("..");
//			}
//			addAmount = GoldfishReader.readInt("还要补票吗（输入正数补票，0退出）");
//			while (true){
//				if (addAmount <= 0) break;
//				if (system.addTickets(addAmount))	break;
//				addAmount=GoldfishReader.readInt("补票无效");
//			}
//			if (addAmount <= 0) break;
//			system.startSale();
		System.out.println("系统运行完毕，欢迎下次使用");
		System.exit(0);

	}
}
class TicketSaleSystem{
	LinkedList<Ticket> tickets;
	LinkedList<BasicBuyer> basicBuyerQueue;
	ReentrantLock lock;
	Condition condition;
	int maxTicketAmount,releasedTicketAmount;
	TicketSaleSystem(){}
	TicketSaleSystem(int maxTicketAmount, int initTicketAmount,int buyerAmount)
	throws InvalidTicketAmountException{
		if(false) {
		}else if(initTicketAmount<=0) {
			throw new InvalidTicketAmountException(initTicketAmount);
		}else if (maxTicketAmount<=0) {
			throw new InvalidTicketAmountException(maxTicketAmount);
		}else if (buyerAmount<=0) {
			throw new InvalidTicketAmountException(buyerAmount);
		}else if (initTicketAmount>maxTicketAmount) {
			throw new InvalidTicketAmountException(maxTicketAmount, initTicketAmount);
		}else if (buyerAmount<maxTicketAmount) {
			throw new InvalidTicketAmountException(maxTicketAmount-buyerAmount,true);
		}

		tickets=new LinkedList<>();
		basicBuyerQueue =new LinkedList<>();
		this.maxTicketAmount=maxTicketAmount;
		lock=new ReentrantLock();
		condition= lock.newCondition();

		addTickets(initTicketAmount);
		this.releasedTicketAmount=initTicketAmount;

		while (basicBuyerQueue.size()<buyerAmount)
			basicBuyerQueue.add(new BasicBuyer(basicBuyerQueue.size()+1));
	}
	TicketSaleSystem(int ticketAmount,int buyerAmount){
		this(ticketAmount,ticketAmount,buyerAmount);
	}
	public Ticket buy(){
		lock.lock();
		try{
			if (tickets.isEmpty()) return null;
			return tickets.removeFirst();
		}finally {
			lock.unlock();
		}
	}
	public void startSale(){
		for(BasicBuyer basicBuyer : basicBuyerQueue) 	basicBuyer.start();
	}
	public boolean addTickets(int addNum){
		if(addNum+releasedTicketAmount>maxTicketAmount){
			System.out.println("发行过量");
			return false;
		}
		for(int i=0;i<addNum;i++){
			try{tickets.add(new Ticket((int) (Math.random() * maxTicketAmount)));}
			catch (Ticket.TicketOrderedException e){i--;}
		}
		return true;
	}

	@Override
	public String toString() {
		int i=0;
		StringBuffer stringBuffer=new StringBuffer();
		for(Ticket ticket:tickets)
			stringBuffer
					.append((++i))
					.append("\t:")
					.append(ticket.seatNum)
					.append("\n");
		return new String(stringBuffer);
	}
	static class InvalidTicketAmountException
			extends RuntimeException{
		public InvalidTicketAmountException(int invalidNum) {
			super(invalidNum+":数字无效");
		}
		public InvalidTicketAmountException(int plannedAmount, int amountAfterRequest) {
			super("放票过量"+(amountAfterRequest-plannedAmount)+"张");
		}
		public InvalidTicketAmountException(int invalidNum,boolean positive){
			super("过量"+invalidNum);
		}
	}
}
class Ticket{
	static LinkedList<Integer> orderedSeats=new LinkedList<>();
	int seatNum;
	public Ticket(int seatNum) throws TicketOrderedException {
		for(int num:orderedSeats)	if(seatNum==num)
			throw new TicketOrderedException(seatNum);
		this.seatNum = seatNum;
		orderedSeats.add(seatNum);
	}
	static class TicketOrderedException extends Exception{
		public TicketOrderedException(int invalidSeatNum) {
			this.invalidSeatNum = invalidSeatNum;
		}
		@Override
		public String getMessage() {
			return "已有座号"+this.invalidSeatNum;
		}
		int invalidSeatNum;
	}

	@Override
	public String toString() {
		return "Ticket{" +
				"seatNum=" + seatNum +
				'}';
	}
}
class BasicBuyer extends Thread{
	Ticket ticket;
	int num;
	int speed;
	int trial;
	int maxTrial;
	boolean finished;
	ReentrantLock reentrantLock;
	Condition condition;
	public BasicBuyer(int num){this(num,2);}
	public BasicBuyer(){
		this(0);
	}
	public BasicBuyer(int num, int trialNum){
		this(trialNum,num,new ReentrantLock());

	}

	public BasicBuyer(
			int maxTrial,int num,
			ReentrantLock reentrantLock) {
		this.maxTrial = maxTrial;
		this.reentrantLock = reentrantLock;
		this.condition = reentrantLock.newCondition();
		this.num=num;
		trial=0;
		finished=false;
		ticket=null;
		this.speed=(int)(Math.random()*5000);
	}

	@Override
	public void run() {
		try{
			Thread.sleep(speed);
		}catch (InterruptedException e){}
		finished=false;
		while (!finished&&trial<maxTrial)	synchronized (System.out)
		{
			try {
				System.out.println(num+"号顾客：");
				if(trial>0) System.out.println("再试一次");
				if((ticket = BasicTicketSaleSystem.system.buy())!=null){
						System.out.println("抢到票了，座号为"+ticket.seatNum);
						finished=true;
				}
				else	System.out.println("没抢到票");
			} catch (IllegalMonitorStateException e) {
				System.out.println("系统繁忙");
			}finally {trial++;}
		}
		finished=true;
		if(trial>=maxTrial)
			System.out.println("算了，先不试了");
	}
}
